home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / sox.zip / HCOM.C < prev    next >
C/C++ Source or Header  |  1992-06-15  |  11KB  |  476 lines

  1. /*
  2.  * September 25, 1991
  3.  * Copyright 1991 Guido van Rossum And Sundry Contributors
  4.  * This source code is freely redistributable and may be used for
  5.  * any purpose.  This copyright notice must be maintained. 
  6.  * Guido van Rossum And Sundry Contributors are not responsible for 
  7.  * the consequences of using this software.
  8.  */
  9.  
  10. /*
  11.  * Sound Tools Macintosh HCOM format.
  12.  * These are really FSSD type files with Huffman compression,
  13.  * in MacBinary format.
  14.  * To do: make the MacBinary format optional (so that .data files
  15.  * are also acceptable).  (How to do this on output?)
  16.  */
  17.  
  18. #include "st.h"
  19.  
  20. #ifdef __STDC__
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #else
  24. extern char *malloc(), *realloc();
  25. #endif
  26.  
  27. /* Dictionary entry for Huffman (de)compression */
  28. typedef struct {
  29.     long frequ;
  30.     short dict_leftson;
  31.     short dict_rightson;
  32. } dictent;
  33.  
  34. /* Private data used by reader */
  35. struct readpriv {
  36.     /* Static data from the header */
  37.     dictent *dictionary;
  38.     long checksum;
  39.     int deltacompression;
  40.     /* Engine state */
  41.     long huffcount;
  42.     long cksum;
  43.     int dictentry;
  44.     int nrbits;
  45.     unsigned long current;
  46.     short sample;
  47. };
  48.  
  49. /*void*/ hcomstartread(ft)
  50. ft_t ft;
  51. {
  52.     struct readpriv *p = (struct readpriv *) ft->priv;
  53.     int i;
  54.     char buf[4];
  55.     unsigned long datasize, rsrcsize;
  56.     unsigned long huffcount, checksum, compresstype, divisor;
  57.     unsigned short dictsize;
  58.  
  59.     /* Skip first 65 bytes of header */
  60.     skipbytes(ft, 65);
  61.  
  62.     /* Check the file type (bytes 65-68) */
  63.     if (fread(buf, 1, 4, ft->fp) != 4 || strncmp(buf, "FSSD", 4) != 0)
  64.         fail("Mac header type is not FSSD");
  65.  
  66.     /* Skip to byte 83 */
  67.     skipbytes(ft, 83-69);
  68.  
  69.     /* Get essential numbers from the header */
  70.     datasize = rblong(ft); /* bytes 83-86 */
  71.     rsrcsize = rblong(ft); /* bytes 87-90 */
  72.  
  73.     /* Skip the rest of the header (total 128 bytes) */
  74.     skipbytes(ft, 128-91);
  75.  
  76.     /* The data fork must contain a "HCOM" header */
  77.     if (fread(buf, 1, 4, ft->fp) != 4 || strncmp(buf, "HCOM", 4) != 0)
  78.         fail("Mac data fork is not HCOM");
  79.  
  80.     /* Then follow various parameters */
  81.     huffcount = rblong(ft);
  82.     checksum = rblong(ft);
  83.     compresstype = rblong(ft);
  84.     if (compresstype > 1)
  85.         fail("Bad compression type in HCOM header");
  86.     divisor = rblong(ft);
  87.     if (divisor == 0 || divisor > 4)
  88.         fail("Bad sampling rate divisor in HCOM header");
  89.     dictsize = rbshort(ft);
  90.  
  91.     /* Translate to sox parameters */
  92.     ft->info.style = UNSIGNED;
  93.     ft->info.size = BYTE;
  94.     ft->info.rate = 22050 / divisor;
  95.     ft->info.channels = 1;
  96.  
  97.     /* Allocate memory for the dictionary */
  98.     p->dictionary = (dictent *) malloc(511 * sizeof(dictent));
  99.     if (p->dictionary == NULL)
  100.         fail("can't malloc memory for Huffman dictionary");
  101.  
  102.     /* Read dictionary */
  103.     for(i = 0; i < dictsize; i++) {
  104.         p->dictionary[i].dict_leftson = rbshort(ft);
  105.         p->dictionary[i].dict_rightson = rbshort(ft);
  106.         /*
  107.         report("%d %d",
  108.                p->dictionary[i].dict_leftson,
  109.                p->dictionary[i].dict_rightson);
  110.                */
  111.     }
  112.     skipbytes(ft, 1); /* skip pad byte */
  113.  
  114.     /* Initialized the decompression engine */
  115.     p->checksum = checksum;
  116.     p->deltacompression = compresstype;
  117.     if (!p->deltacompression)
  118.         report("HCOM data using value compression");
  119.     p->huffcount = huffcount;
  120.     p->cksum = 0;
  121.     p->dictentry = 0;
  122.     p->nrbits = -1; /* Special case to get first byte */
  123. }
  124.  
  125. /*void*/ skipbytes(ft, n)
  126. ft_t ft;
  127. int n;
  128. {
  129.     while (--n >= 0) {
  130.         if (getc(ft->fp) == EOF)
  131.             fail("unexpected EOF in Mac header");
  132.     }
  133. }
  134.  
  135. int hcomread(ft, buf, len)
  136. ft_t ft;
  137. long *buf, len;
  138. {
  139.     register struct readpriv *p = (struct readpriv *) ft->priv;
  140.     int done = 0;
  141.  
  142.     if (p->nrbits < 0) {
  143.         /* The first byte is special */
  144.         if (p->huffcount == 0)
  145.             return 0; /* Don't know if this can happen... */
  146.         p->sample = getc(ft->fp);
  147.         if (p->sample == EOF)
  148.             fail("unexpected EOF at start of HCOM data");
  149.         *buf++ = (p->sample - 128) * 0x1000000;
  150.         p->huffcount--;
  151.         p->nrbits = 0;
  152.         done++;
  153.         len--;
  154.         if (len == 0)
  155.             return done;
  156.     }
  157.  
  158.     while (p->huffcount > 0) {
  159.         if(p->nrbits == 0) {
  160.             p->current = rblong(ft);
  161.             if (feof(ft->fp))
  162.                 fail("unexpected EOF in HCOM data");
  163.             p->cksum += p->current;
  164.             p->nrbits = 32;
  165.         }
  166.         if(p->current & 0x80000000) {
  167.             p->dictentry =
  168.                 p->dictionary[p->dictentry].dict_rightson;
  169.         } else {
  170.             p->dictentry =
  171.                 p->dictionary[p->dictentry].dict_leftson;
  172.         }
  173.         p->current = p->current << 1;
  174.         p->nrbits--;
  175.         if(p->dictionary[p->dictentry].dict_leftson < 0) {
  176.             short datum;
  177.             datum = p->dictionary[p->dictentry].dict_rightson;
  178.             if (!p->deltacompression)
  179.                 p->sample = 0;
  180.             p->sample = (p->sample + datum) & 0xff;
  181.             p->huffcount--;
  182.             if (p->sample == 0)
  183.                 *buf++ = -127 * 0x1000000;
  184.             else
  185.                 *buf++ = (p->sample - 128) * 0x1000000;
  186.             p->dictentry = 0;
  187.             done++;
  188.             len--;
  189.             if (len == 0)
  190.                 break;
  191.         }
  192.     }
  193.  
  194.     return done;
  195. }
  196.  
  197. /*void*/ hcomstopread(ft) 
  198. ft_t ft;
  199. {
  200.     register struct readpriv *p = (struct readpriv *) ft->priv;
  201.  
  202.     if (p->huffcount != 0)
  203.         fail("not all HCOM data read");
  204.     if(p->cksum != p->checksum)
  205.         fail("checksum error in HCOM data");
  206.     free((char *)p->dictionary);
  207.     p->dictionary = NULL;
  208. }
  209.  
  210. struct writepriv {
  211.     unsigned char *data;    /* Buffer allocated with malloc */
  212.     unsigned int size;    /* Size of allocated buffer */
  213.     unsigned int pos;    /* Where next byte goes */
  214. };
  215.  
  216. #define BUFINCR (10*BUFSIZ)
  217.  
  218. /*void*/ hcomstartwrite(ft) 
  219. ft_t ft;
  220. {
  221.     register struct writepriv *p = (struct writepriv *) ft->priv;
  222.  
  223.     switch (ft->info.rate) {
  224.     case 22050:
  225.     case 22050/2:
  226.     case 22050/3:
  227.     case 22050/4:
  228.         break;
  229.     default:
  230.         fail("unacceptable output rate for HCOM: try 5512, 7350, 11025 or 22050 hertz");
  231.     }
  232.     ft->info.size = BYTE;
  233.     ft->info.style = UNSIGNED;
  234.     ft->info.channels = 1;
  235.  
  236.     p->size = BUFINCR;
  237.     p->pos = 0;
  238.     p->data = (unsigned char *) malloc(p->size);
  239.     if (p->data == NULL)
  240.         fail("can't malloc buffer for uncompressed HCOM data");
  241. }
  242.  
  243. /*void*/ hcomwrite(ft, buf, len)
  244. ft_t ft;
  245. long *buf, len;
  246. {
  247.     register struct writepriv *p = (struct writepriv *) ft->priv;
  248.     long datum;
  249.  
  250.     if (p->pos + len > p->size) {
  251.         p->size = ((p->pos + len) / BUFINCR + 1) * BUFINCR;
  252.         p->data = (unsigned char *) realloc(p->data, p->size);
  253.         if (p->data == NULL)
  254.             fail("can't realloc buffer for uncompressed HCOM data");
  255.     }
  256.  
  257.     while (--len >= 0) {
  258.         datum = *buf++;
  259.         datum >>= 24;
  260.         datum ^= 128;
  261.         p->data[p->pos++] = datum;
  262.     }
  263. }
  264.  
  265. /*void*/ hcomstopwrite(ft) 
  266. ft_t ft;
  267. {
  268.     register struct writepriv *p = (struct writepriv *) ft->priv;
  269.     unsigned char *data = p->data;
  270.     long len = p->pos;
  271.     int i;
  272.  
  273.     /* Compress it all at once */
  274.     compress(&data, &len, (double) ft->info.rate);
  275.     free((char *) p->data);
  276.  
  277.     /* Write the header */
  278.     (void) fwrite("\000\001A", 1, 3, ft->fp); /* Dummy file name "A" */
  279.     padbytes(ft, 65-3);
  280.     (void) fwrite("FSSD", 1, 4, ft->fp);
  281.     padbytes(ft, 83-69);
  282.     wblong(ft, (unsigned long) len); /* data size */
  283.     wblong(ft, (unsigned long) 0); /* rsrc size */
  284.     padbytes(ft, 128 - 91);
  285.     if (ferror(ft->fp))
  286.         fail("write error in HCOM header");
  287.  
  288.     /* Write the data fork */
  289.     if (fwrite((char *) data, 1, (int)len, ft->fp) != len)
  290.         fail("can't write compressed HCOM data");
  291.     free((char *) data);
  292.  
  293.     /* Pad the data fork to a multiple of 128 bytes */
  294.     padbytes(ft, 128 - (int) (len%128));
  295. }
  296.  
  297. /*void*/ padbytes(ft, n)
  298. ft_t ft;
  299. int n;
  300. {
  301.     while (--n >= 0)
  302.         putc('\0', ft->fp);
  303. }
  304.  
  305.  
  306. /* XXX This uses global variables -- one day these should all be
  307.    passed around in a structure instead. */
  308.  
  309. void putlong(c, v)
  310. unsigned char *c;
  311. long v;
  312. {
  313.   *c++ = (v >> 24) & 0xff;
  314.   *c++ = (v >> 16) & 0xff;
  315.   *c++ = (v >> 8) & 0xff;
  316.   *c++ = v & 0xff;
  317. }
  318.  
  319. void putshort(c, v)
  320. unsigned char *c;
  321. short v;
  322. {
  323.   *c++ = (v >> 8) & 0xff;
  324.   *c++ = v & 0xff;
  325. }
  326.  
  327. dictent dictionary[511];
  328. dictent *de;
  329. long codes[256];
  330. long codesize[256];
  331. long checksum;
  332.  
  333. void makecodes(e, c, s, b)
  334. int e, c, s, b;
  335. {
  336.   if(dictionary[e].dict_leftson < 0) {
  337.     codes[dictionary[e].dict_rightson] = c;
  338.     codesize[dictionary[e].dict_rightson] = s;
  339.   } else {
  340.     makecodes(dictionary[e].dict_leftson, c, s + 1, b << 1);
  341.     makecodes(dictionary[e].dict_rightson, c + b, s + 1, b << 1);
  342.   }
  343. }
  344.  
  345. long curword;
  346. int nbits;
  347.  
  348. void putcode(c, df)
  349. unsigned char c;
  350. unsigned char ** df;
  351. {
  352. long code, size;
  353. int i;
  354.   code = codes[c];
  355.   size = codesize[c];
  356.   for(i = 0; i < size; i++) {
  357.     curword = (curword << 1);
  358.     if(code & 1) curword += 1;
  359.     nbits++;
  360.     if(nbits == 32) {
  361.       putlong(*df, curword);
  362.       checksum += curword;
  363.       (*df) += 4;
  364.       nbits = 0;
  365.       curword = 0;
  366.     }
  367.     code = code >> 1;
  368.   }
  369. }
  370.  
  371. /*void*/ compress(df, dl, fr)
  372. unsigned char **df;
  373. long *dl;
  374. float fr;
  375. {
  376.   long huffcount, compresstype, samplerate;
  377.   unsigned char *datafork = *df;
  378.   unsigned char *ddf;
  379.   short dictsize;
  380.   unsigned char *uncompressed;
  381.   int frequtable[256];
  382.   int i, sample, j, k, d, l, frequcount;
  383.  
  384.   sample = *datafork;
  385.   for(i = 0; i < 256; i++) frequtable[i] = 0;
  386.   for(i = 1; i < *dl; i++) {
  387.     d = datafork[i] - sample & 0xff;
  388.     sample = datafork[i];
  389.     datafork[i] = d;
  390.     frequtable[d]++;
  391.   }
  392.   de = dictionary;
  393.   for(i = 0; i < 256; i++) if(frequtable[i] != 0) {
  394.     de->frequ = -frequtable[i];
  395.     de->dict_leftson = -1;
  396.     de->dict_rightson = i;
  397.     de++;
  398.   }
  399.   frequcount = de - dictionary;
  400.   for(i = 0; i < frequcount; i++) {
  401.     for(j = i + 1; j < frequcount; j++) {
  402.       if(dictionary[i].frequ > dictionary[j].frequ) {
  403.         k = dictionary[i].frequ;
  404.         dictionary[i].frequ = dictionary[j].frequ;
  405.         dictionary[j].frequ = k;
  406.         k = dictionary[i].dict_leftson;
  407.         dictionary[i].dict_leftson = dictionary[j].dict_leftson;
  408.         dictionary[j].dict_leftson = k;
  409.         k = dictionary[i].dict_rightson;
  410.         dictionary[i].dict_rightson = dictionary[j].dict_rightson;
  411.         dictionary[j].dict_rightson = k;
  412.       }
  413.     }
  414.   }
  415.   while(frequcount > 1) {
  416.     j = frequcount - 1;
  417.     de->frequ = dictionary[j - 1].frequ;
  418.     de->dict_leftson = dictionary[j - 1].dict_leftson;
  419.     de->dict_rightson = dictionary[j - 1].dict_rightson;
  420.     l = dictionary[j - 1].frequ + dictionary[j].frequ;
  421.     for(i = j - 2; i >= 0; i--) {
  422.       if(l >= dictionary[i].frequ) break;
  423.       dictionary[i + 1] = dictionary[i];
  424.     }
  425.     i = i + 1;
  426.     dictionary[i].frequ = l;
  427.     dictionary[i].dict_leftson = j;
  428.     dictionary[i].dict_rightson = de - dictionary;
  429.     de++;
  430.     frequcount--;
  431.   }
  432.   dictsize = de - dictionary;
  433.   for(i = 0; i < 256; i++) {
  434.     codes[i] = 0;
  435.     codesize[i] = 0;
  436.   }
  437.   makecodes(0, 0, 0, 1);
  438.   l = 0;
  439.   for(i = 0; i < 256; i++) {
  440.       l += frequtable[i] * codesize[i];
  441.   }
  442.   l = (((l + 31) >> 5) << 2) + 24 + dictsize * 4;
  443.   report("  Original size: %6d bytes", *dl);
  444.   report("Compressed size: %6d bytes", l);
  445.   if((datafork = (unsigned char *)malloc((unsigned)l)) == NULL)
  446.     fail("can't malloc buffer for compressed HCOM data");
  447.   ddf = datafork + 22;
  448.   for(i = 0; i < dictsize; i++) {
  449.     putshort(ddf, dictionary[i].dict_leftson);
  450.     ddf += 2;
  451.     putshort(ddf, dictionary[i].dict_rightson);
  452.     ddf += 2;
  453.   }
  454.   *ddf++ = 0;
  455.   *ddf++ = *(*df)++;
  456.   checksum = 0;
  457.   nbits = 0;
  458.   curword = 0;
  459.   for(i = 1; i < *dl; i++) putcode(*(*df)++, &ddf);
  460.   if(nbits != 0) {
  461.     codes[0] = 0;
  462.     codesize[0] = 32 - nbits;
  463.     putcode(0, &ddf);
  464.   }
  465.   strncpy(datafork, "HCOM", 4);
  466.   putlong(datafork + 4, *dl);
  467.   putlong(datafork + 8, checksum);
  468.   putlong(datafork + 12, 1L);
  469.   samplerate = 22050 / (long)fr;
  470.   putlong(datafork + 16, samplerate);
  471.   putshort(datafork + 20, dictsize);
  472.  
  473.   *df = datafork;
  474.   *dl = l;
  475. }
  476.